#pragma once

#include <string>

#include "call_agent_interface.hpp"
#include "api/p2pms_client_interface.hpp"
#include "video_renderer_manager.hpp"

namespace p2pms
{

//==================================================================================================
// 
//==================================================================================================
class P2PMSClientImpl : public ICallHandler
{
public:
	P2PMSClientImpl();
	~P2PMSClientImpl();

	ErrCode Init(IMainThreadExecutor* executor, IClientHandler* handler, 
		const std::string& server_addr, rtc::Thread* thread);
	ErrCode Login(const std::string& user_id);
	void Logout();
	std::vector<std::string> GetUserList();
	ErrCode MakeCall(CallMode mode, const std::string& callee_id);
	void TerminateCall();
	ErrCode StartPublish(const MediaDevice& device, MediaInfo& media);
	ErrCode StopPublish(const MediaInfo& media);
	ErrCode StartSubscribe(const std::string& user_id, const MediaInfo& media);
	ErrCode StopSubscribe(const std::string& user_id, const MediaInfo& media);
	IRendererManager* GetRendererManager();
	IDeviceManager* GetDeviceManager();
	
private:
	// ICallHandler interface methods
	void OnCallStateChanged(std::string call_id, CallState state) override;
	void OnStartPublish(const std::string& user_id, const MediaInfo& media) override;
	void OnStopPublish(const std::string& user_id, const MediaInfo& media) override;
	void OnStartPublishResult(const MediaInfo& media, bool result) override;
	void OnStopPublishResult(const MediaInfo& media, bool result) override;
	void OnStartSubscribeResult(const std::string& user_id, const MediaInfo& media,
		bool result) override;
	void OnStopSubscribeResult(const std::string& user_id, const MediaInfo& media,
		bool result) override;
	void OnAddTrack(const std::string& user_id, const MediaInfo& media,
		rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track) override;
	void OnRemoveTrack(const std::string& user_id, const MediaInfo& media) override;

private:
	void OnLoginRes(const Message& msg, CBType cbt);
	void OnLoginNotify(const Message& msg, CBType cbt);
	void OnLogoutNotify(const Message& msg, CBType cbt);
	void OnDispatcherEvent(DispatcherEventType event_type);
	void OnCallNotify(const Message& msg, CBType cbt);
	bool CreatePeerConnectionFactory();
	void ScheduleTimer();
	void OnTimer();
	bool InitMsgDispatcher(const std::string& server_addr);
	bool CreateWebRtcThreads();
	void SendCallMakeAck(const std::string& rid, int code, const std::string& msg, 
		const CallMakeNotifyData& notify_data);

private:
	IMainThreadExecutor* m_main_thread_executor = nullptr;
	IClientHandler* m_client_handler = nullptr;
	rtc::Thread* m_sdk_thread = nullptr;
	std::shared_ptr<IMsgDispatcher> m_msg_dispatcher;
	std::string m_room_id;
	std::string m_user_id;

	IPcFactoryPtr m_pc_factory = nullptr;

	std::unique_ptr<VideoRendererManager> m_renderer_manager;

	std::vector<std::string> m_online_user_list;

	std::mutex m_init_mutex;
	std::shared_ptr<std::promise<bool>> m_init_promise;

	bool m_logined = false;

	std::shared_ptr<ICallAgent> m_call_agent;

	std::unique_ptr<rtc::Thread> m_network_thread;
	std::unique_ptr<rtc::Thread> m_signaling_thread;
	std::unique_ptr<rtc::Thread> m_worker_thread;

	bool m_timer_running = true;

	std::map<std::string, std::string> m_media_id_map;
};

}